import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.text.*;
import java.applet.*;

class Gui extends JFrame {
   public static final AudioClip correctSound=
      Util.getAudioClip("sounds/Temple.wav");
   public static final AudioClip[] wrongSound=new AudioClip[] {
      Util.getAudioClip("sounds/Quack.wav"),
      Util.getAudioClip("sounds/Uh_oh.wav"),
      Util.getAudioClip("sounds/Laugh.wav"),
      Util.getAudioClip("sounds/Boing.wav"),
      Util.getAudioClip("sounds/ChuToy.wav"),
      Util.getAudioClip("sounds/Wild_Eep.wav"),
   };
   public static final AudioClip finishSound=
      Util.getAudioClip("sounds/Indigo.wav");
   public final static Font font64 = new Font("Dialog", Font.PLAIN, 64);
   public final static Font font32 = new Font("Dialog", Font.PLAIN, 24);

   Exam exam=null;
   private final ConfigPane configPane=new ConfigPane(this);

   public Gui() {
      setTitle("Memo");
      setBounds(100, 100, 400, 300);
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      showConfig();
      //pack();
   }
   public static void main(String[] args) {
      final Gui gui=new Gui();
      gui.setVisible(true);
   }
   public void showConfig() {
      setContentPane(configPane);
      configPane.revalidate();
      repaint();
   }
   public void startExam(
         String s, String e, int o, boolean f, boolean r, boolean rnd) {
      exam=new Exam(s, e, o, f, r, rnd);
      final ExamPane ePane=new ExamPane(this, exam);
      setContentPane(ePane);
      ePane.revalidate();
      repaint();
   }
   public void reviewExam() {
      exam.review();
      final ExamPane ePane=new ExamPane(this, exam);
      setContentPane(ePane);
      ePane.revalidate();
      repaint();
   }
   public void quitExam() {
      final ReportPane rPane=new ReportPane(this, exam);
      setContentPane(rPane);
      rPane.revalidate();
      repaint();
      //finishSound.play();
   }
}

class ExamPane extends JPanel {
   final Exam exam;
   final JLabel questionLabel=new JLabel();
   final ButtonGroup bg=new ButtonGroup();
   final JRadioButton[] options;
   final JLabel indexLabel=new JLabel();
   final Gui mainWindow;

   public ExamPane(Gui mw, Exam test) {
      mainWindow=mw;
      exam=test;
      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      setBackground(Color.white);
      options=new JRadioButton[exam.numOfOptions];
      //setBorder(BorderFactory.createLineBorder(Color.red));
      
      //[ commands
      final JButton quitButton=new JButton("Quit");
      final JButton nextButton=new JButton("Next");
      quitButton.setMnemonic(KeyEvent.VK_N);
      quitButton.setAlignmentX(LEFT_ALIGNMENT);
      quitButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            mainWindow.quitExam();
         }
      });
      this.add(quitButton);

      //[ question
      indexLabel.setAlignmentX(CENTER_ALIGNMENT);
      indexLabel.setFont(Gui.font32);
      add(indexLabel);

      questionLabel.setAlignmentX(CENTER_ALIGNMENT);
      questionLabel.setFont(Gui.font64);
      add(questionLabel);

      //[ options
      //states:
      //unanswered ---   make a choice   --> answered
      //           <-- click button next --- 
      final ActionListener optionListener=new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            //System.err.println(e.getActionCommand());
            
            for(int i=0; i<exam.numOfOptions; i++) {
               options[i].setEnabled(false);
            }

            int ans=Integer.valueOf(e.getActionCommand());
            options[exam.getCurrentQuestion().answer].setOpaque(true);
            if(exam.check(ans)) {
               Gui.correctSound.play();
               options[ans].setBackground(Color.green);
               //System.err.println("right");
            } else {
               //options[ans].setForeground(Color.gray);
               //Gui.wrongSound[Util.random.nextInt(Gui.wrongSound.length)].play();
               Gui.wrongSound[0].play();
               options[exam.getCurrentQuestion().answer].setBackground(Color.red);
               //options[answerIndex].setBorder(BorderFactory.createLineBorder(Color.red, 2));

               //System.err.println("wrong");
            }
            nextButton.requestFocus();
            
            //[ show answers of the options
            for(int i=0; i<exam.numOfOptions; i++) {
               options[i].setText(options[i].getText()+
                     " <-> "+
                     exam.getCurrentQuestion().getChoicePrompt(i));
            }

            repaint();
         }
      };
      //int optionShortcut=KeyEvent.VK_1;
      for(int i=0; i<exam.numOfOptions; i++) {
         options[i]=new JRadioButton(i+")");
         options[i].setFont(Gui.font32);
         options[i].setAlignmentX(CENTER_ALIGNMENT);
         options[i].addActionListener(optionListener);
         //rb.setAccelerator(KeyStroke.getKeyStroke(optionShortcut, 0));
         bg.add(options[i]);
         this.add(options[i]);
      }

      //[ fill in data
      if(!exam.hasNext()) throw new RuntimeException("empty set");
      exam.next();
      fillData();

      //[ commands
      nextButton.setMnemonic(KeyEvent.VK_N);
      nextButton.setAlignmentX(CENTER_ALIGNMENT);
      nextButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if(exam.hasNext()) {
               //System.err.println("!");
               exam.next();
               fillData();
            } else {
               //System.out.println("Congratulations!");
               mainWindow.quitExam();
            }
         }
      });
      this.add(nextButton);

   }

   private void resetOptions(ButtonGroup optionGroup) {
      optionGroup.clearSelection();
      for(int i=0; i<options.length; i++) {
         options[i].setBackground(Color.gray);
         //options[i].setSelected(false);
         options[i].setEnabled(true);
         options[i].setOpaque(false);
      }
   }
   private void fillData() {
//System.err.println(exam.index);
      //Card currentCard=exam.allCards.get(exam.index);
      resetOptions(bg);
      indexLabel.setText((exam.index)+"/"+exam.questions.size());
      final int qidx=exam.getCurrentQuestion().problem;
      if(!exam.isFlipped) {
         questionLabel.setText(exam.allCards.get(qidx).getFront());
      } else {
         questionLabel.setText(exam.allCards.get(qidx).getBack());
      }

      for(int i=0; i<exam.numOfOptions; i++) {
         final int idx=exam.getCurrentQuestion().options[i];
         options[i].setActionCommand(Integer.toString(i));
         if(!exam.isFlipped) {
            options[i].setText(exam.allCards.get(idx).getBack());
         } else {
            options[i].setText(exam.allCards.get(idx).getFront());
         }
      }

      /*
      final Random random=new Random();
      exam.answerIndex=random.nextInt(exam.numOfOptions);
      int optionIndex=exam.answerIndex;
      options[optionIndex++].setText(currentCard.getBack());

      for(int i=0; i<exam.numOfOptions-1; i++) {
         final Card randomCard=exam.allCards.get(random.nextInt(exam.allCards.size()));
         options[optionIndex%exam.numOfOptions].setText(randomCard.getBack());
         optionIndex++;
         //>>> eliminate duplicate entry
      }
      */
   }
}
class ConfigPane extends JPanel {
   private Gui mainWindow;
   public ConfigPane(Gui mw) {
      mainWindow=mw;
      setLayout(new BorderLayout());

      final JPanel upperPane=new JPanel();
      upperPane.setLayout(new BoxLayout(upperPane, BoxLayout.Y_AXIS));
      upperPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
      add(upperPane, BorderLayout.NORTH);

      final JLabel rangeLabel=new JLabel("Range: ");
      final JTextField startField=new JTextField(10);
      final JLabel toLabel=new JLabel(" to ");
      final JTextField endField=new JTextField(10);
      upperPane.add(createFlow(rangeLabel, startField, toLabel, endField));


      //final JLabel qLabel=new JLabel("Number of Questions: ");
      final JLabel oLabel=new JLabel("Number of Options: ");
      final JSpinner oSpinner=new JSpinner(new SpinnerNumberModel(
            3, 1, 10, 1));
      upperPane.add(createFlow(oLabel, oSpinner));

      final JCheckBox fBox=new JCheckBox();
      fBox.setText("Flip Cards");
      fBox.setAlignmentX(LEFT_ALIGNMENT);
      upperPane.add(fBox);

      final JCheckBox rBox=new JCheckBox();
      rBox.setText("Restrict Option Ranges");
      rBox.setAlignmentX(LEFT_ALIGNMENT);
      rBox.setSelected(true);
      upperPane.add(rBox);

      final JCheckBox sBox=new JCheckBox();
      sBox.setText("Randomize");
      sBox.setAlignmentX(LEFT_ALIGNMENT);
      sBox.setSelected(true);
      upperPane.add(sBox);

      final JButton startButton=new JButton("Start");
      startButton.setAlignmentX(LEFT_ALIGNMENT);
      startButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            final String start=startField.getText().trim(); 
            String end=endField.getText().trim(); 
            if(end.isEmpty()) end=start;
            final int num=(Integer)oSpinner.getModel().getValue();

            mainWindow.startExam(
               start, end, num, 
               fBox.getModel().isSelected(),
               rBox.getModel().isSelected(),
               sBox.getModel().isSelected());
         }
      });
      add(createFlow(startButton), BorderLayout.SOUTH);
   }
   private JPanel createFlow(JComponent ... childs) {
      final JPanel parent=new JPanel();
      parent.setAlignmentX(LEFT_ALIGNMENT);
      parent.setLayout(new FlowLayout(FlowLayout.LEFT));
      //parent.setBorder(BorderFactory.createLineBorder(Color.red, 5));
      for(JComponent child: childs) {
         parent.add(child);
      }
      return parent;
   }
}
class ReportPane extends JPanel {
   final Gui mainWindow;
   final Exam exam;
   public ReportPane(Gui mw, Exam test) {
      mainWindow=mw;
      exam=test;
      setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

      final int finalScore=Math.round(exam.getScore());
      final String scoreStr=
         new DecimalFormat("0.##").format(finalScore)+"%";

      final String start=exam.allCards.get(exam.startIndex).getFront();
      final String end=exam.allCards.get(exam.endIndex).getFront();
      final JLabel promptLabel=new JLabel(
            String.format("From '%s' to '%s'(%d in total)", 
               start, end, exam.total));
      //promptLabel.setFont(Gui.font32);
      promptLabel.setAlignmentX(CENTER_ALIGNMENT);
      add(promptLabel);

      final JLabel scoreLabel=new JLabel(scoreStr);
      scoreLabel.setFont(Gui.font64);
      scoreLabel.setAlignmentX(CENTER_ALIGNMENT);
      add(scoreLabel);

      final JButton reviewButton=new JButton("Review");
      reviewButton.setAlignmentX(CENTER_ALIGNMENT);
      reviewButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            mainWindow.reviewExam();
         }
      });
      add(reviewButton);

      final JButton okButton=new JButton("OK");
      okButton.setAlignmentX(CENTER_ALIGNMENT);
      okButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            mainWindow.showConfig();
         }
      });
      add(okButton);
      
   }
}
/*
class Config {
   public Config(String s, String e, int o) {
      start=s;
      end=e;
      numberOfOptions=o;
   }
}
*/
/*
class MultiFlowLayout implements LayoutManager {
   public void layoutContainer(Container container) {}
   public Dimension minimumLayoutSize(Container container) {}
   public Dimension preferredLayoutSize(Container container) {}
   public void addLayoutComponent(Component component) {}
   public void addLayoutComponent(String s, Component component) {}
   public void removeLayoutComponent(Component component) {}
}
*/
/*
//window layouts

ConfigPane:
   Range: from ? to ?
   //Number of Questions: ?
   Number of Options: ?
   Start
Exam:
   Question
   Option1
   Option2
   ...
   //Previous
   Next
   Quit
ScoreReport:
   Label: Congratulations! Your score is:
   Label: ?%
   OK
   Again
*/
